/*****************************************************************************
 *  CommLayerLib - SerialLayer.java
 *  Copyright (C) 2012  Matteo Piscitelli
 *  E-mail: matteo@picciux.it
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *  For further info, check http://code.google.com/p/java-comm-layer/
 *
 *  SVN: $Id: SerialLayer.java 41 2012-10-11 16:35:35Z picciux@gmail.com $
 *  
 *****************************************************************************/

package it.picciux.commlayer.serial;

import it.picciux.commlayer.CommLayer;
import it.picciux.commlayer.ConfigValue;

public abstract class SerialLayer extends CommLayer {
	public class Settings extends CommLayer.Settings {

		public static final int DATABITS_5 = 5;
		public static final int DATABITS_6 = 6;
		public static final int DATABITS_7 = 7;
		public static final int DATABITS_8 = 8;
		public static final int PARITY_NONE = 0;
		public static final int PARITY_ODD = 1;
		public static final int PARITY_EVEN = 2;
		public static final int PARITY_MARK = 3;
		public static final int PARITY_SPACE = 4;
		public static final int STOPBITS_1 = 1;
		public static final int STOPBITS_2 = 2;
		public static final int STOPBITS_1_5 = 3;
		public static final int FLOWCONTROL_NONE = 0;
		public static final int FLOWCONTROL_XONXOF = 1;	
		public static final int FLOWCONTROL_RTSCTS = 2;
		
		
		private String port = "";
		private int baudRate = 9600;
		private int dataBits = DATABITS_8;
		private int stopBits = STOPBITS_1;
		private int parity = PARITY_NONE;
		private int flowControl = FLOWCONTROL_NONE;
		
		//private static final long serialVersionUID = 2001L;
		private int fieldIndex;
		
		public boolean setPort (String port) {
			this.port = port;
			return true;
		}
		
		public boolean setBaudRate (int baudRate) {
			this.baudRate = baudRate;
			return true;
		}

		public boolean setDataBits(int dataBits) {
			this.dataBits = dataBits;
			return true;
		}
		
		public boolean setStopBits(int stopBits) {
			this.stopBits = stopBits;
			return true;
		}

		public boolean setParity(int parity) {
			this.parity = parity;
			return true;
		}

		public boolean setFlowControl(int flowControl) {
			this.flowControl = flowControl;
			return true;
		}
		
		/* config management */
		public boolean setConfigValue(ConfigValue v) {
			if (v.getKey().equalsIgnoreCase("port"))
				port = v.getValueString();

			else if (v.getKey().equalsIgnoreCase("baudRate"))
				baudRate = v.getValueInt();

			else if (v.getKey().equalsIgnoreCase("dataBits"))
				dataBits = v.getValueInt();

			else if (v.getKey().equalsIgnoreCase("stopBits"))
				stopBits = v.getValueInt();

			else if (v.getKey().equalsIgnoreCase("parity"))
				parity = v.getValueInt();

			else if (v.getKey().equalsIgnoreCase("flowControl"))
				flowControl = v.getValueInt();

			else return false;
			
			return true;
		}
		
		public ConfigValue getNextConfig() {
			ConfigValue ret;
			
			switch(fieldIndex) {
				case 0:
					ret = new ConfigValue("port", port);
					break;
				case 1:
					ret = new ConfigValue("baudRate", baudRate); 
					break;
				case 2:
					ret = new ConfigValue("dataBits", dataBits); 
					break;
				case 3:
					ret = new ConfigValue("stopBits", stopBits); 
					break;
				case 4:
					ret =  new ConfigValue("parity", parity); 
					break;
				case 5:
					ret =  new ConfigValue("flowControl", flowControl);
					break;
				default:
					return null;
			}
			
			fieldIndex++;
			return ret;
		}

		
		public it.picciux.commlayer.CommLayer.Settings clone() {
			Settings c = new Settings();
			c.baudRate = baudRate;
			c.dataBits = dataBits;
			c.flowControl = flowControl;
			c.parity = parity;
			c.stopBits = stopBits;
			c.port = new String(port);
			return c;
		}
		
		public int[] getBaudRateValues() {
			int[] ret = new int[] {
				4800,
				9600,
				14400,
				28800,
				38400,
				57600,
				115200
			};
			
			return ret;
		}

		public int[] getDataBitsValues() {
			int[] ret = new int[] {
				DATABITS_8,
				DATABITS_7,
				DATABITS_6,
				DATABITS_5
			};
			
			return ret;
		}

		public int[] getParityValues() {
			int[] ret = new int[] {
				PARITY_NONE,
				PARITY_ODD,
				PARITY_EVEN,
				PARITY_MARK,
				PARITY_SPACE
			};
			
			return ret;
		}

		public int[] getStopBitsValues() {
			int[] ret = new int[] {
				STOPBITS_1,
				STOPBITS_1_5,
				STOPBITS_2
			};
				
			return ret;
		}

		public int[] getFlowControlValues() {
			int[] ret = new int[] {
				FLOWCONTROL_NONE,
				FLOWCONTROL_XONXOF,
				FLOWCONTROL_RTSCTS
			};
			
			return ret;
			
		}

		public String getParityValue2String(int value) {
			switch(value) {
				case PARITY_ODD:
					return "ODD";
				case PARITY_EVEN:
					return "EVEN";
				case PARITY_MARK:
					return "MARK";
				case PARITY_SPACE:
					return "SPACE";
				default:					// NONE
					return "NONE";				
			}
		}

		public String getFlowControlValue2String(int value) {
			switch(value) {
			case FLOWCONTROL_XONXOF:
				return "XONXOFF";
			case FLOWCONTROL_RTSCTS:
				return "RTSCTS";
			default:					// NONE
				return "NONE";				
			}
		}

		public int getParityString2Value(String s) {
			if (s.equalsIgnoreCase("ODD"))
				return PARITY_ODD;
			
			else if (s.equalsIgnoreCase("EVEN"))
				return PARITY_EVEN;
			
			else if (s.equalsIgnoreCase("MARK"))
				return PARITY_MARK;
			
			else if (s.equalsIgnoreCase("SPACE"))
				return PARITY_SPACE;
			
			else 
				return PARITY_NONE;
		}

		public int getFlowControlString2Value(String s) {
			if (s.equalsIgnoreCase("XONXOFF"))
				return FLOWCONTROL_XONXOF;
			
			else if (s.equalsIgnoreCase("RTSCTS"))
				return FLOWCONTROL_RTSCTS;
			
			else 
				return FLOWCONTROL_NONE;
		}

		/**
		 * @return the port
		 */
		public String getPort() {
			return port;
		}

		/**
		 * @return the baudRate
		 */
		public int getBaudRate() {
			return baudRate;
		}

		/**
		 * @return the dataBits
		 */
		public int getDataBits() {
			return dataBits;
		}

		/**
		 * @return the stopBits
		 */
		public int getStopBits() {
			return stopBits;
		}

		/**
		 * @return the parity
		 */
		public int getParity() {
			return parity;
		}

		/**
		 * @return the flowControl
		 */
		public int getFlowControl() {
			return flowControl;
		}
		
	}

	public static final int NO_SUCH_PORT = (SERIAL * 100) + 0;
	public static final int PORT_IS_NOT_COM = (SERIAL * 100) + 1;
	
	public SerialLayer() {
		settings = new Settings();
	}

	public boolean canScan() {
		return true;
	}

	public it.picciux.commlayer.CommLayer.Settings getSettings() {
		return settings;
	}
	
	public int getType() {
		return CommLayer.SERIAL;
	}

	public abstract boolean scan();
	public abstract void cancelScan();
	
}
